<?php

namespace App\GameChannel\Sdks;

use App\GameChannel\LoginNotify;
use App\GameChannel\PayNotify;
use App\GameChannel\SdkBase;
use App\Models\Orders;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class QuickSdk extends SdkBase
{
    // 配置渠道号关系，用于解决账号互通问题
    protected $channelCodeList = [
        2326 => 2326,   // 爱趣安卓
        2327 => 2326,   // 爱趣ios
        259  => 259,    // 小七安卓
        240  => 259,    // 小七ios
        2491 => 2491,   // 直播安卓
        2492 => 2491,   // 直播ios
        1728 => 1728,   // 一元安卓
        1908 => 1728,   // 一元ios
        2149 => 2149,   // 斑马
        2150 => 2149,   // 斑马
    ];

    private static function getBytes($string) {
        $bytes = [];
        for($i = 0; $i < strlen($string); $i++){
             $bytes[] = ord($string[$i]);
        }
        return $bytes;
    }

    private static function toStr($bytes) {
        $str = '';
        foreach($bytes as $ch) {
            $str .= chr($ch);
        }
   		return $str;
    }

    private function decode($str, $key) {
		if(empty($str)){
			return $str;
		}
		preg_match_all('(\d+)', $str, $list);
		$list = $list[0];
		if (count($list) > 0) {
			$key = self::getBytes($key);
			for ($i = 0; $i < count($list); $i++) {
				$keyVar = $key[$i % count($key)];
				$data[$i] =  $list[$i] - (0xff & $keyVar);
			}
			return self::toStr($data);
		} else {
			return $str;
		}
	}

    public function login(Request $request): LoginNotify
    {
        $notify = $this->loginNotify;

        $token      = $request['access_token'];
        $uid        = $request['openid'];
        $channel_id = $request['extend_1'];
        $appid      = $this->gameChannel['appid'];

        $url = "http://checkuser.quickapi.net/v2/checkUserInfo";
        $params = [
            'token'        => $token,
            'uid'          => $uid,
            'product_code' => $appid,
        ];

        $response = Http::get($url, $params);
        if (!$response->ok()) {
            $notify->errno = 41159;
            return $notify;
        }

        $body = $response->body();
        if ($body != '1') {
            $notify->errno = 41159;
            return $notify;
        }

        $channel_code = $this->channelCodeList[$channel_id] ?? $channel_id;
        $notify->openid = "{$channel_code}-{$uid}";

        return $notify;
    }

    // 将xml转为array
    private function fromXml(string $xml)
    {
        $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $json = json_encode($xml);
        $data = json_decode($json, true);

        return $data;
    }

    // 处理充值回调
    public function payCb(Request $request, $cb_type): PayNotify
    {
        $notify = $this->payNotify;
        $params = $request->all();

        // 校验签名
        $check_sign = md5($params['nt_data'] . $params['sign'] . $this->gameChannel['paykey']);
        if ($check_sign != $params['md5Sign']) {
            $notify->errno = 6011;
            return $notify;
        }

        // 数据解密
        $data = $this->decode($params['nt_data'], $this->gameChannel['appsecret']);
        $data = $this->fromXml($data)['message'];

        // 校验订单
        $trade_no = $data['game_order'];
        $order    = Orders::where('trade_no', $trade_no)->first();
        if (!$order) {
            $notify->errno = 6011;
            return $notify;
        }

        // 如果此订单已经被处理过
        if ($order->status != Orders::PAY_STATUS_CREATE) {
            $notify->errno = 6012;
            return $notify;
        }

        // 校验充值金额
        if (abs($order->amount - floatval($data['amount'])) > 1) {
            $notify->errno = 6013;
            return $notify;
        }

        // 校验用户
        $channel_id = $data['channel'];
        $channel_code = $this->channelCodeList[$channel_id] ?? $channel_id;
        $channel_openid = "{$channel_code}-{$data['channel_uid']}";
        if ($order->channel_openid != $channel_openid) {
            $notify->errno = 6014;
            return $notify;
        }

        $notify->order          = $order;
        $notify->tradeNo        = $trade_no;
        $notify->channelTradeNo = $data['order_no'];
        $notify->isTest         = $data['is_test'] == 1?1:0;
        return $notify;
    }

    public function supplementOrderInfo()
    {
        $notify = $this->payNotify;
        $order = $notify->order;
        $order->is_test = $notify->isTest;

        return true;
    }

    public function payOk()
    {
        return 'SUCCESS';
    }

    public function payErr()
    {
        if ($this->payNotify->errno == 6012) {
            return 'SUCCESS';
        }

        return yqerr($this->payNotify->errno);
    }
}
